package com.baofu.paycore.service.processor.preAuth;

import com.baofu.clear.service.facade.enums.EventTypeEnum;
import com.baofu.paycore.biz.external.clear.EventService;
import com.baofu.paycore.biz.external.clear.model.EventRuleResBO;
import com.baofu.paycore.common.enums.FundTypeEnum;
import com.baofu.paycore.common.exception.PayCoreBizException;
import com.baofu.paycore.service.facade.enums.PayCoreErrorCode;
import com.baofu.paycore.common.utils.Constant;
import com.baofu.paycore.dal.mapper.SubPreAuthMapper;
import com.baofu.paycore.dal.model.SubPreAuthDO;
import com.baofu.paycore.manager.model.preAuth.PreAuthBO;
import com.baofu.paycore.manager.model.preAuth.SubPreAuthBO;
import com.baofu.paycore.service.facade.enums.PayStatusEnums;
import com.baofu.paycore.service.facade.enums.PayToolSubTypeEnum;
import com.baofu.paycore.service.facade.enums.PayToolTypeEnum;
import com.baofu.paycore.service.facade.model.authconfirm.AuthConfirmDTO;
import com.baofu.paycore.service.facade.model.pay.FundDetailInfoDTO;
import com.baofu.paycore.service.processor.PayBaseProcessor;
import com.google.common.collect.Lists;
import com.system.commons.exception.BizServiceException;
import com.system.commons.sequence.redis.SequenceFacade;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * 预授权完成资金单
 *
 * User: xin deng  Date: 16/9/1 ProjectName: paycore Version: 1.0
 */
@Slf4j
@Component
public class SubPreAuthConfirmProcessor implements PayBaseProcessor<PreAuthBO, AuthConfirmDTO> {

    /**
     * 资金单明细NO
     */
    @Autowired
    private SequenceFacade sequenceFacade;

    /**
     * 预授权资金单
     */
    @Autowired
    private SubPreAuthMapper subPreAuthMapper;

    /**
     * 会计事件服务
     */
    @Autowired
    private EventService eventService;

    /**
     * 支付内部对象构建
     *
     * @param payBaseBO  支付模型
     * @param payBaseDTO 请求参数
     */
    @Override
    public PayBaseProcessor process(PreAuthBO payBaseBO, AuthConfirmDTO payBaseDTO) {
        if (StringUtils.isEmpty(payBaseDTO.getOrigPayNo())) {
            log.error("原支付单号不存在 预授权信息preAuthBO:{}", payBaseBO);
            throw new PayCoreBizException(PayCoreErrorCode.ORIG_PAY_NO_NOT_EXIST);
        }
        SubPreAuthDO subPreAuthDO = subPreAuthMapper.selectSubPreAuthByPayNo(payBaseDTO.getOrigPayNo(),
                FundTypeEnum.PRE_AUTH.getCode());
        if (null == subPreAuthDO) {
            log.error("原支付单号:{} 预授权子单信息不存在", payBaseDTO.getOrigPayNo());
            throw new PayCoreBizException(PayCoreErrorCode.SUB_ORDER_IS_NOT_EXISTED, "预授权子单信息不存在");
        }
        List<SubPreAuthBO> subPreAuthBOs = Lists.newArrayList();
        FundDetailInfoDTO fundDetailInfoDTO = payBaseDTO.getFundDetailInfoDTO();
        //预授权完成手续费单
        if (Constant.validateLong(fundDetailInfoDTO.getBizChargeAmount()) > 0) {
            SubPreAuthBO feeSubPreAuth = getSubPreAuthBO(payBaseDTO, payBaseBO, null,
                    fundDetailInfoDTO.getBizFeeAccount(), fundDetailInfoDTO.getBizChargeAmount(),
                    FundTypeEnum.PRE_AUTH_CONFIRM_FEE.getCode());
            subPreAuthConvert(feeSubPreAuth, subPreAuthDO);
            feeSubPreAuth.setPayToolType(PayToolTypeEnum.ACCOUNT.getCode());
            feeSubPreAuth.setPayToolSubType(PayToolSubTypeEnum.ACCOUNT.getSubPayToolCode());
            //手续费会计事件
            feeSubPreAuth.setEventNo(eventProcessor(payBaseDTO));
            subPreAuthBOs.add(feeSubPreAuth);
        }
        //预授权完成资金单
        SubPreAuthBO subPreAuthBO = getSubPreAuthBO(payBaseDTO, payBaseBO, payBaseDTO.getPayee(),
                subPreAuthDO.getPayerAccNo(), payBaseDTO.getAmt(), FundTypeEnum.PRE_AUTH_CONFIRM.getCode());
        subPreAuthConvert(subPreAuthBO, subPreAuthDO);
        subPreAuthBOs.add(subPreAuthBO);

        payBaseBO.setSubPreAuthBO(subPreAuthBOs);
        return this;
    }

    /**
     * 预授权完成资金单对象转换
     *
     * @param authConfirmDTO        预授权确认对象
     * @param preAuthBO             预授权BO对象
     * @param payeeAccNo            入账账户
     * @param amt                   入账金额
     * @param fundType              资金单类型
     * @return                      预授权完成资金单
     */
    private SubPreAuthBO getSubPreAuthBO(AuthConfirmDTO authConfirmDTO,PreAuthBO preAuthBO, String payeeAccNo,
                                         String payerAccNo, Long amt, String fundType){
        FundDetailInfoDTO fundDetailInfoDTO = authConfirmDTO.getFundDetailInfoDTO();
        SubPreAuthBO subPreAuthBO = new SubPreAuthBO();
        subPreAuthBO.setFundDetailNo(sequenceFacade.getUniqueSeq());
        subPreAuthBO.setFreezeNo(sequenceFacade.getUniqueSeq());
        subPreAuthBO.setFundType(fundType);
        subPreAuthBO.setStatus(PayStatusEnums.INIT.getCode());
        subPreAuthBO.setPayNo(preAuthBO.getPayNo());
        subPreAuthBO.setPayToolType(fundDetailInfoDTO.getPayToolType());
        subPreAuthBO.setPayToolSubType(fundDetailInfoDTO.getPayToolSubType());
        subPreAuthBO.setAmt(amt);
        subPreAuthBO.setCcy(authConfirmDTO.getCcy());
        subPreAuthBO.setPayeeAccNo(payeeAccNo);
        subPreAuthBO.setPayerAccNo(payerAccNo);
        subPreAuthBO.setFdDtlExtra(fundDetailInfoDTO.getFundDetailExt() != null ?
                fundDetailInfoDTO.getFundDetailExt().toString() : null);

        return subPreAuthBO;
    }

    /**
     * 值转换
     *
     * @param subPreAuthBO      预授权资金单BO对象
     * @param subPreAuthDO      预授权资金单DO对象
     */
    private void subPreAuthConvert(SubPreAuthBO subPreAuthBO, SubPreAuthDO subPreAuthDO){
        subPreAuthBO.setFundingChannel(subPreAuthDO.getFundingChannel());
        subPreAuthBO.setSubFundingChannel(subPreAuthDO.getSubFundingChannel());
        subPreAuthBO.setRelateFundDetailNo(subPreAuthDO.getRelateFundDetailNo());
        //预授权冻结码
        subPreAuthBO.setFreezeCode(subPreAuthDO.getFreezeCode());
    }

    /**
     * 会计事件处理流程
     *
     * @param authConfirmDTO     预授权确认
     * @return                   事件号
     */
    private String eventProcessor(AuthConfirmDTO authConfirmDTO) {

        FundDetailInfoDTO fundDetailInfoDTO = authConfirmDTO.getFundDetailInfoDTO();
        if (null == fundDetailInfoDTO) {
            return null;
        }
        long chargeAmt = Constant.validateLong(fundDetailInfoDTO.getBizChargeAmount());
        if (chargeAmt > 0) {
            EventRuleResBO eventRuleResBO = eventService.queryEventNo(EventTypeEnum.FEE, authConfirmDTO.getSubBizType());
            if (!Objects.equals(eventRuleResBO.getStatus(), PayStatusEnums.SUCCESS.getCode())) {
                log.error("会计事件不存在:{}",authConfirmDTO.getBizType());
                throw new BizServiceException(PayCoreErrorCode.EVENT_NO_NOT_EXIST, eventRuleResBO.getErrorMsg());
            }
            return eventRuleResBO.getEventNo();
        }
        return null;
    }
}
